// 字符串操作的函数实现
#include <string.h>
#include <stdio.h>
#include <stdint.h>
#include <sys/types.h> 
#include <cstdint>
#include <stdlib.h>
#include <stdarg.h>// va_list

#include "global.h"
#include "my_string.h"

//截取字符串尾部空格
void Rtrim(char *string)   
{   
	size_t len = 0;   
	if(string == NULL) {
        return;
    }  
		   
	len = strlen(string);   
	while(len > 0 && string[len-1] == ' '){
        string[--len] = 0;
    }
}

//截取字符串首部空格
void Ltrim(char *string)
{
	size_t len = 0;
	len = strlen(string);   
	char *p_tmp = string;
	if(p_tmp[0] != ' '){// 不是以空格开头
        return;
    }
		
	//找第一个不为空格的
	while(p_tmp[0] != '\0')
	{
		if(p_tmp[0] == ' ')
			p_tmp++;
		else
			break;
	}

     //如果首位为\0说明字符串已经没了，原字符串全是空格
	if(p_tmp[0] == '\0')
	{
		*string = '\0';
		return;
	}

	char *p_tmp2 = string; 
	while((*p_tmp) != '\0')
	{
		(*p_tmp2) = (*p_tmp);
		p_tmp++;
		p_tmp2++;
	}
	(*p_tmp2) = '\0';// 添加结束标志
}

// 安全版格式化函数，通过缓冲区末尾指针防止溢出
u_char *Slprintf(u_char *buf, u_char *last, const char *fmt, ...){
    va_list args;// va_list类型变量用来接收可变长参数
    u_char *p;

    va_start(args, fmt);// 初始化 args，使其指向可变参数的起始位置
    p = Vslprintf(buf, last, fmt, args);
    va_end(args);// 释放args
    return p;
}

// 安全版格式化函数，通过最大长度限定防止溢出
u_char *Snprintf(u_char *buf, size_t max, const char *fmt, ...){
    va_list args;// va_list类型变量用来接收可变长参数
    u_char *p;

    va_start(args, fmt);// 初始化 args，使其指向可变参数的起始位置
    p = Vslprintf(buf, buf + max, fmt, args);
    va_end(args);// 释放args
    return p;
}

// 上面两个格式化函数的公共处理模块，是通过尾指针防止溢出
// 允许的格式：%d数字、%s字符串、%f浮点数、%P进程号
u_char *Vslprintf(u_char *buf, u_char *last, const char *fmt, va_list args){
    // 定义一个跨平台的指针兼容整数类型 uintptr_t用于安全地将指针转换为整数
    #ifdef _WIN64
        typedef unsigned __int64  uintptr_t;
    #else
        typedef unsigned int uintptr_t;
    #endif
    
    u_char zero;// 用于表示零值或空格,作为填充字符
    uintptr_t width;// 格式化宽度（如 %10d 中的 10）
    uintptr_t sign;// 符号标志（如 %+d 的 +）
    uintptr_t hex;// 十六进制标志（如 %x、%X）
    uintptr_t frac_width;// 小数部分宽度（如 %.2f 中的 2）
    uintptr_t scale;// 可能用于浮点数缩放（如科学计数法）
    uintptr_t n;
    int64_t i64;// 保存%d对应的可变参
    uint64_t ui64;// 保存%ud对应的可变参，临时作为%f可变参的整数部分也是可以的
    u_char *p;// 保存%s对应的可变参
    double f;// 保存%f对应的可变参
    uint64_t frac;// %f可变参数,根据%.2f等，取得小数部分的2位后的内容；

    // 循环处理，每次处理一个字符
    while(*fmt && buf < last){
        // %开头的一般是需要被可变参数取代的
        if(*fmt == '%'){
            // 变量初始化工作
            zero = (u_char)((*++fmt == '0') ? '0' : ' ');// 判断%后边接的是否是个'0',如果是zero = '0'，否则zero = ' '
            width = 0;// 格式化宽度（如 %10d 中的 10）
            sign  = 1;// 是否是有符号数,如果用%u表示无符号
            hex   = 0;// 是否以16进制形式显示0：不是，1：是，并以小写字母显示a-f，2：是，并以大写字母显示A-F
            frac_width = 0;// 小数部分宽度（如 %.2f 中的 2）
            i64 = 0;// %d对应的可变参中的实际数字
            ui64 = 0;// %ud对应的可变参中的实际数字

            // 判断%后的是不是数字，是就取出放到width中
            while (*fmt >= '0' && *fmt <= '9'){
                width = width * 10 + (*fmt++ - '0');
            }

            // 循环处理%后的特殊字符u、X、x、.
            for( ;; ){// 相当于while(1)
                switch (*fmt){
                    case 'u':{
                        sign = 0;
                        fmt++;
                        continue;
                    }
                    case 'X':{
                        hex = 2;
                        sign = 0;
                        fmt++;
                        continue;
                    }
                    case 'x':{
                        hex = 1;
                        sign = 0;
                        fmt++;
                        continue;
                    }
                    case '.':{
                        fmt++;
                        // 读取浮点数位数
                        while(*fmt >= '0' && *fmt <= '9'){
                            frac_width = frac_width * 10 + (*fmt++ - '0');
                        }
                        break;
                    }
                    default:{
                        break; 
                    }
                }
                break;
            }

            // 其他情况，%、d、i、L、p、s、P、f、
            switch (*fmt){
                case '%':{// 只有%%时才会遇到这个情形，本意是打印一个%
                    *buf++ = '%';
                    fmt++;
                    continue;
                }
                case 'd':{
                    // 根据是否有符号进一步处理
                    if (sign){
                        i64 = (int64_t) va_arg(args, int);// va_arg():遍历可变参数，var_arg的第二个参数表示遍历的这个可变的参数的类型
                    }
                    else{
                        ui64 = (uint64_t) va_arg(args, u_int);
                    }
                    break;
                }
                case 'i':{
                    if (sign){
                        i64 = (int64_t) va_arg(args, intptr_t);
                    }
                    else{
                        ui64 = (uint64_t) va_arg(args, uintptr_t);
                    }
                    break;
                }
                case 'L':{// 转换int64j型数据，如果用%uL，则转换的数据类型是uint64 t
                    if (sign){
                        i64 = va_arg(args, int64_t);
                    }
                    else{
                        ui64 = va_arg(args, uint64_t);
                    }
                    break;
                }
                case 'p':{
                    ui64 = (uint64_t) va_arg(args, void *);
                    hex = 2;    //标记以大写字母显示十六进制中的A-F
                    sign = 0;   //标记这是个无符号数
                    zero = '0'; //前边0填充
                    width = 2 * sizeof(void *);
                    break;
                }
                case 's':{
                    p = va_arg(args, u_char *);
                    if (p == NULL) {
                        static u_char null_str[] = "(null)";
                        p = null_str;
                    }
                    while (*p && buf < last){
                        *buf++ = *p++;
                    }
                    fmt++;
                    continue;
                }
                case 'P':{
                    i64 = (int64_t) va_arg(args, pid_t);
                    sign = 1;
                    break;
                }
                case 'f':{
                    f = va_arg(args, double);
                    // 如果是负数
                    if (f < 0){
                        *buf++ = '-';
                        f = -f;
                    }
                    ui64 = (int64_t) f;
                    frac = 0;

                    // 处理保留小数
                    if (frac_width){
                        scale = 1;
                        for (n = frac_width; n; n--){
                            scale *= 10;// 可能溢出
                        }

                        // 取得保留的那些小数位数，比如 %.2f + 12.537 => 54；%.6f + 21.378 => 378000
                        frac = (uint64_t) ((f - (double) ui64) * scale + 0.5);
                        // 如果发生进位，那么小数结果会等于缩放的值
                        if (frac == scale){
                            ui64++;    //正整数部分进位
                            frac = 0;  //小数部分归0
                        }
                    }

                    // 添加正整数部分
                    buf = Sprintf_num(buf, last, ui64, zero, 0, width);
                    // 如果指定了显示多少位小数
                    if (frac_width){
                        if (buf < last){
                            *buf++ = '.'; // 因为指定显示多少位小数，先把小数点增加进来
                        }
                        buf = Sprintf_num(buf, last, frac, '0', 0, frac_width);
                    }
                    fmt++;
                    continue;
                }
                default:{
                    *buf++ = *fmt++;
                    continue;// 注意这个continue其实是continue到外层的while去了
                }
            }

            // 能走到这的是%d的，其他格式的日后再说
            if (sign){
                if (i64 < 0){
                    *buf++ = '-';
                    ui64 = (uint64_t) -i64;// 变成无符号数（正数）
                }
                else{
                    ui64 = (uint64_t) i64;
                }
            }

            // 将数字放到buf中，不够位数补空格
            // 第5个参数hex表示是否16进制表示，匹配%Xd或%xd
            buf = Sprintf_num(buf, last, ui64, zero, hex, width);
            fmt++;
        }
        // 如果是普通字符，不是%
        else{
            *buf++ = *fmt++; 
        }
    }
    return buf;
}

// 将整数数字字符串转换为指定宽度的正整数并添加到缓冲区中函数,不够会填充0或空格
static u_char *Sprintf_num(u_char *buf, u_char *last, uint64_t ui64,u_char zero, uintptr_t hexadecimal, uintptr_t width){
    u_char *p, temp[INT64_LEN + 1];
    size_t len;
    uint32_t ui32;

    static u_char   hex[] = "0123456789abcdef";
    static u_char   HEX[] = "0123456789ABCDEF";

    p = temp + INT64_LEN;// p指向数组的最后一个元素

    // 如果不是以16进制显示
    if (hexadecimal == 0){
        // 如果在最大的32位无符号数范围内
        if (ui64 <= (uint64_t) MAX_UINT32_VALUE){
            ui32 = (uint32_t) ui64;// 可以保存
            // 拆分每一位到数组中,数组最后一位留着
            do// 比如将123存为temp[17] = 1 temp[18] = 2 temp[19] = 3
            {
                *--p = (u_char) (ui32 % 10 + '0');
            } while (ui32 /= 10);
        }
        else{
            do
            {
                *--p = (u_char) (ui64 % 10 + '0');
            } while (ui64 /= 10); 
        }
    }
    // 如果开启16进制，并且字母用小写
    else if(hexadecimal == 1){
        do
        {
            // 0xf就是二进制的1111, ui64 & 0xf位运算就是把一个数的最末尾的4个二进制位拿出来
            *--p = hex[(uint32_t) (ui64 & 0xf)];
        }while(ui64 >>= 4);// 每次移动四位，因为4位二进制对应一位16进制
    }
    // 如果开启16进制，并且字母用大写
    else{
        do
        {
            // 0xf就是二进制的1111, ui64 & 0xf位运算就是把一个数的最末尾的4个二进制位拿出来
            *--p = HEX[(uint32_t) (ui64 & 0xf)];
        }while(ui64 >>= 4);// 每次移动四位，因为4位二进制对应一位16进制
    }

    len = (temp + INT64_LEN) - p;// 得到这个数字的宽度

    // 凑够显示的宽度（可能需要填充）
    while (len++ < width && buf < last){
        *buf++ = zero;// zero是填充用，值是0或空格
    }

    // 还原len，因为上面while循环改变了它
    len = (temp + INT64_LEN) - p;

    // 准备进行拷贝，剩下有多少buf就拷贝多少
    if((buf + len) >= last){
        len = last - buf;
    }
    return cpymem(buf, p, len);
}


